Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step2 아토 #2

Open
wants to merge 27 commits into
base: hyxrxn
Choose a base branch
from

Conversation

hyxrxn
Copy link
Member

@hyxrxn hyxrxn commented Apr 23, 2024

리팩토링은 하나도... 안되어 있습니다
기능 구현만 되어있어요

왜 이렇게 했느냐?
라고 물어본다면
학습 테스트에 그렇게 되어있어서...
라고 대답할 수밖에 없는 상태입니다... 대부분요.
리팩토링 추천 부분! 위주로 코멘트 주시면 감사하겠습니다

다들 홧팅

hyxrxn and others added 5 commits April 18, 2024 00:24
* feat(RoomEscapeController): 홈 화면 생성

Co-authored-by: hyxrxn <[email protected]>

* feat(RoomEscapeController): welcome page 리다이렉트

Co-authored-by: hyxrxn <[email protected]>

* feat(RoomEscapeController): 예약 내역 조회

Co-authored-by: hyxrxn <[email protected]>

* refactor(ReservationDto): 예약 정보 전달

Co-authored-by: hyxrxn <[email protected]>

* style(RoomEscapeApplication): 불필요한 개행 삭제

Co-authored-by: hyxrxn <[email protected]>

* feat(RoomEscapeController): 예약 추가

Co-authored-by: hyxrxn <[email protected]>

* feat(RoomEscapeController): 예약 삭제

Co-authored-by: hyxrxn <[email protected]>

* style(RoomEscapeController): 개행 추가

Co-authored-by: hyxrxn <[email protected]>

* refactor(ReservationResponse): 클래스명 변경

Co-authored-by: hyxrxn <[email protected]>

* fix(index.html): 페이지 이동 불가 버그 개선

Co-authored-by: hyxrxn <[email protected]>

* refactor(controller): 컨트롤러 분리

Co-authored-by: hyxrxn <[email protected]>

* style(controller): 디폴트값 명시

Co-authored-by: hyxrxn <[email protected]>

* refactor(ReservationRequest): LocalDateTime 변환 로직 수정

Co-authored-by: hyxrxn <[email protected]>

* style(import): import문 순서 컨벤션 적용

Co-authored-by: hyxrxn <[email protected]>

* refactor(Reservation): 불필요한 생성자 제거

* refactor(ReservationRequest): 래퍼 클래스 이용하게 통일

---------

Co-authored-by: Arachneee <[email protected]>
- 예약 추가 시 해당 예약 바디로 리턴
- reservation-legacy.js에서 상태코드 수정
Copy link
Member

@robinjoon robinjoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아토 화이팅!!


@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class MissionStepTest {
class MissionStepTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 테스트 코드는 End to End 테스트라고 볼 수 있어요.
단위 테스트나 통합 테스트가 작성될 필요가 있겠네요.

Comment on lines 14 to 16
public Reservation toReservation(Long id) {
return new Reservation(id, name, LocalDateTime.of(date, time));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request DTO가 도메인을 아는 구조네요.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용하지 않는 메서드더라구요.... 삭제해버렸습니다

Comment on lines 9 to 10
String date,
String time
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

타입을 String으로 정의한건 그냥 LMS 따라한건가요? 각각 날짜와 시간에 특화된 타입을 사용하는 것은 어떨까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

따라한거 맞습니다...!
특화된 타입을 사용하면 뭐가 좋나요??
저는 어차피 body에 전달되는 모양이 똑같을거라고 생각해서 이대로 뒀습니다

this.jdbcTemplate = jdbcTemplate;
}

@GetMapping("")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 경우에는 ("") 를 아예 생략하고 @GetMapping 이라 할 수 있어요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오오 대박 이유를 설명할 게 있긴 있었네요

이건 일부러 붙였습니다!
다 붙이는 것을 컨벤션으로 정하면 실수를 줄일 수 있을 것 같아서 페어와 합의를 했습니다
실수로 빼먹고 안 붙인건지 아니면 없어도 돼서 생략한건지 구분이 되니까요... ㅎㅎ

Comment on lines 73 to 81
(resultSet, rowNum) ->
new Reservation(
resultSet.getLong("id"),
resultSet.getString("name"),
LocalDateTime.of(
resultSet.getDate("date").toLocalDate(),
resultSet.getTime("time").toLocalTime()
)
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RowMapper를 따로 클래스로 빼는건 어떨까요?

class MissionStepTest {

@Autowired
private JdbcTemplate jdbcTemplate;

@Test
void 일단계() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드 이름을 바꿔보는건 어떨까요?

Copy link

@kelly6bf kelly6bf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 아토! 아무래도 미션 크기가 작다 보니 리뷰 드릴 내용이 별로 없네요..! 👀 Spring 학습이 이번이 처음이라고 들었는데 요구사항들을 잘 구현하고 있어서 대단하다는 생각이 들었습니다! (코딩은 역시 뇌지컬이구나..)

PR에 작성하신 대로 최대한 개선해 보면 좋을 부분들에 대해서 리뷰를 작성해 봤어요! 혹시 리뷰 내용 중 이해되지 않거나 잘못된 부분이 있으면 언제든 질문 주세요! 앞으로의 미션도 파이팅!!

PS. 시간에 쫓겨서 리뷰를 작성하다 보니 띄어쓰기가 좀 개판입니당.. 다음번에 리뷰를 또 하게 된다면 그때는 맞춤법 검사기도 한 번 돌라셔 올릴게요! 가독성이 많이 떨어지셨다면 죄송.. 😢 (그래도 이 코멘트는 돌렸습니다..ㅎ)

@Controller
public class AdminController {

@GetMapping("")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RequestMapping에 설정된 Base URL을 그대로 요청한다면 다음과 같이 ""를 제거하고 작성할 수도 있습니다!

@GetMapping
public String admin() {
    return "admin/index";
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로빈에게 답변한 것을 복붙하겠습니닷

#2 (comment)

오오 대박 이유를 설명할 게 있긴 있었네요

이건 일부러 붙였습니다!
다 붙이는 것을 컨벤션으로 정하면 실수를 줄일 수 있을 것 같아서 페어와 합의를 했습니다
실수로 빼먹고 안 붙인건지 아니면 없어도 돼서 생략한건지 구분이 되니까요... ㅎㅎ

@Controller
public class HomeController {

@GetMapping("")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

역시 마찬가지로 ""를 제거하고 사용할 수 있어요! 😋

@GetMapping
public String index() {
    return "redirect:/admin";
}


private JdbcTemplate jdbcTemplate;

public ReservationController(JdbcTemplate jdbcTemplate) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

취향차이라고 생각하지만 생성자 파라미터에 final을 붙이는것에 대해서 어떻게 생각하시나요!

IntelliJ는 생성자 자동 생성과 함께 final키워드도 자동으로 붙여주는 설정도 제공하는걸요? 🫣
https://jaehhh.tistory.com/45

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 차이가 있는지 공부해본적이 없어서 생각을 못했네요

차이 먼저 공부해보겠습니다
ㅋㅋㅋㅋㅋㅋ

return ResponseEntity.noContent().build();
}

private List<Reservation> getReservations() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Controller에서 직접 DB에 접근해서 데이터를 조회하고있네요! 아직은 작성할 쿼리의 복잡도가 크지않아서 컨트롤러가 직접 DB에서 데이터를 가져오는 방식에 크게 문제가 없어 보이지만, 만약 쿼리가 더 복잡해진다면? 혹은 수정사항이 생긴다면? 아토의 코드를 처음 접한 동료들은 자연스럽게 어떤 클래스를 먼저 확인해볼까요? 🤔

사실 아토는 이미 Layered architecture가 무엇인지, DB에 직접 쿼리를 전송하고 결과 데이터를 받아오는 작업을 컨트롤러보다 더 잘할 수 있는 친구가 누군인지 알고 있을거라 생각해요! (Re..로 시작하는 친구였나?)

컨트롤러가 많은 것들을 책임지는 코드를 작성해봤으니 이번에는 분리하는 코드를 작성해보는건 어떨까요? 🤭

추가로 컨트롤러가 DB에 직접 접근하는등 많은 역할을 가지고 있는 구조를 Smaprt UI Pattern이라고 불러요! 무조건 Layered architecture로 나누는건 좋고, Smart UI Pattern을 따르는건 좋지않고 보다는 직접 두 구조의 장단점을 찾아보면서 기준을 세워본다면 앞으로의 미션에서도 더 수월하지 않을까 생각해요! ☺️

https://dev.to/ielgohary/layered-architecture-and-smart-ui-domain-driven-design-by-eric-evans-part-ii-chapter-4-1il7

KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(
"insert into reservation (name, date, time) values (?, ?, ?)",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JdbcTemplate을 사용해 쿼리를 작성할때 동적인 파라미터를 설정하기 위해서는 ?을 기준으로 순서에 맞춰 파라미터를 설정해야하죠! 물론 지금처럼 파라미터 개수가 적고 간단한 쿼리라면 지금 방식도 크게 나쁘지 않지만.. 파라미터가 점점 늘어난다면..? 순서 유지를 하는것도 꽤 골치아플 수 있어요!

이런 문제를 먼저 겪은 선배 개발자분들은 NamedParameterJdbcTemplate라는 기술을 내놓으셨습니다! 이번 기회에 찾아보고 적용해보면 팍팍한 우테코 미션이 아주 조금은 개선될지도...? 👀

공식 문서 : https://docs.spring.io/spring-framework/reference/data-access/jdbc/core.html#jdbc-NamedParameterJdbcTemplate
친절한 한국 블로그 : https://code-lab1.tistory.com/278

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안그래도 이번에 코드리뷰를 하며 알게 된 기능이네요...!
링크 첨부까지,,, 너무 감사합니닷🥹

import org.springframework.test.annotation.DirtiesContext;
import roomescape.dto.ReservationResponse;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SpringBootTestSpringBootTest.WebEnvironment.DEFINED_PORT는 어떤 설정일까요? 만약 애플리케이션을 실행한 상태에서 테스트를 수행한다면 어떤일이 발생할까요? 🤔

물론 애플리케이션 끄고 테스트하면 그만 아님?ㅎ라고 한다면 할말이 없지만! 그래도 테스트를 수행할 때 마다 애플리케이션을 끄고키는건 너무 번거로울거 같아요 😢 애플리케이션 실행과 관련없이 @SpringBootTest가 설정된 테스트를 수행할 방법은 없을까요?!

RANDOM_PORT : https://docs.spring.io/spring-boot/reference/testing/spring-boot-applications.html#testing.spring-boot-applications.with-running-server

PS. RANDOM_PORT로 설정했는데.. 에러가 난다고요? 뭐 연결이 안되서 뭐시기 한다고요? 왜 그런 문제가 발생할까요... 어떻게 해결하지 👀
https://stackoverflow.com/questions/40665315/testing-spring-boot-rest-application-with-restassured

- 변수 추출
- 상수 분리
- SimpleJdbcInsert 사용
- 존재한다면 예외 발생
- 존재하지 않는다면 정상 삭제
- 조회 개수가 삭제 이후 1개에서 0개가 되었는지 확인
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants